package end.util.jedis;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang3.SerializationUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.util.CollectionUtils;

/**
 * 
 * ShiroRedisCache.java 2016-7-12
 * 
 * Copyright zhaocj Inc. All rights reserved. Love Me Like Love Justin Bieber
 */
public class ShiroRedisCache<K, V> implements Cache<K, V> {
	private final static Logger logger = LogManager
			.getLogger(ShiroRedisCache.class);
	private ShiroRedisWorker cache;
	private String keyPrefix = "shiro_redis_cache:";

	public String getKeyPrefix() {
		return keyPrefix;
	}

	public void setKeyPrefix(String keyPrefix) {
		this.keyPrefix = keyPrefix;
	}

	public ShiroRedisCache(ShiroRedisWorker cache) {
		if (cache == null) {
			throw new IllegalArgumentException("Cache argument cannot be null.");
		}
		this.cache = cache;
	}

	// 多加了选项可以自定义前缀而已
	public ShiroRedisCache(ShiroRedisWorker cache, String prefix) {
		this(cache);
		this.keyPrefix = prefix;
	}

	private byte[] getByteKey(K key) {
		if (key instanceof String) {
			String preKey = this.keyPrefix + key;
			return preKey.getBytes();
		} else {
			return SerializationUtils.serialize((Serializable) key);
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	public V get(K key) throws CacheException {
		if (logger.isDebugEnabled()) {
			logger.debug("根据key从Redis中获取对象 key [" + key + "]");
		}
		try {
			if (key == null) {
				return null;
			} else {
				byte[] rawValue = cache.get(getByteKey(key));
				V value = null;
				if (rawValue != null) {
					value = (V) SerializationUtils.deserialize(rawValue);
				}
				return value;
			}
		} catch (Throwable t) {
			throw new CacheException(t);
		}
	}

	@Override
	public V put(K key, V value) throws CacheException {
		if (logger.isDebugEnabled()) {
			logger.debug("根据key从redis存储 key [" + key + "]");
		}
		try {
			cache.set(getByteKey(key),
					SerializationUtils.serialize((Serializable) value));
			return value;
		} catch (Throwable t) {
			throw new CacheException(t);
		}
	}

	@Override
	public V remove(K key) throws CacheException {
		if (logger.isDebugEnabled()) {
			logger.debug("从redis中删除 key [" + key + "]");
		}
		try {
			V previous = get(key);
			cache.del(getByteKey(key));
			return previous;
		} catch (Throwable t) {
			throw new CacheException(t);
		}
	}

	@Override
	public void clear() throws CacheException {
		if (logger.isDebugEnabled()) {
			logger.debug("从redis中删除所有元素");
		}
		try {
			cache.flushDB();
		} catch (Throwable t) {
			throw new CacheException(t);
		}
	}

	@Override
	public int size() {
		try {
			Long longSize = new Long(cache.dbSize());
			return longSize.intValue();
		} catch (Throwable t) {
			throw new CacheException(t);
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	public Set<K> keys() {
		try {
			Set<byte[]> keys = cache.keys(this.keyPrefix + "*");
			if (CollectionUtils.isEmpty(keys)) {
				return Collections.emptySet();
			} else {
				Set<K> newKeys = new HashSet<K>();
				for (byte[] key : keys) {
					newKeys.add((K) key);
				}
				return newKeys;
			}
		} catch (Throwable t) {
			throw new CacheException(t);
		}
	}

	@Override
	public Collection<V> values() {
		try {
			Set<byte[]> keys = cache.keys(this.keyPrefix + "*");
			if (!CollectionUtils.isEmpty(keys)) {
				List<V> values = new ArrayList<V>(keys.size());
				for (byte[] key : keys) {
					@SuppressWarnings("unchecked")
					V value = get((K) key);
					if (value != null) {
						values.add(value);
					}
				}
				return Collections.unmodifiableList(values);
			} else {
				return Collections.emptyList();
			}
		} catch (Throwable t) {
			throw new CacheException(t);
		}
	}
}